package MMSServer;

import java.io.*;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.util.StringTokenizer;
import javax.activation.MimetypesFileTypeMap;

import HTTPRecieveParser.*;
import HTTPSendIntegrator.*;
import PUSHSendIntegrator.*;

import java.sql.*;
import DatabaseManager.*;

public class HttpProcess extends Thread {

	private static final String NL = "\r\n";
	
	//MMS Receive Type list
	private static final String MMS_MESSAGE_TYPE_SEND_REQ = "m-send-req";
	private static final String MMS_MESSAGE_TYPE_READ_REPOSRT_REQ = "m-read-report-req";
	private static final String MMS_MESSAGE_TYPE_FORWAD_REQ = "m-forward-req";
	private static final String MMS_MESSAGE_TYPE_ACKNOWLEDGE_IND = "m-acknowledge-ind";
	private static final String MMS_MESSAGE_TYPE_NOTIFY_IND = "m-notify-ind";
	
	// 클라이언트와의 접속 소켓
	private Socket connectionSocket;
	private BufferedReader inFromClient;
	private DataOutputStream outToClient;
	
	private String mmsBody;
	private StringTokenizer tokenizedRequestLine;
	private StringTokenizer tokenizedMmsBody;
	private String strContentLength;
	private int contentLength;
	
	private SendReq sendReqMsg;
	private ReadRecInd readRecIndMsg;
	private ForwardReq forwardReqMsg;	
	private AcknowledgeInd acknowledgeIndMsg;
	private NotifyResp notifyRespMsg;
	
	private HTTPMmsMessage responseHttpMsg;
	
	private String requestMessageLine;
	
	private PushTempBox pushTempBox;
	private PDUMSGBox pduMsgBox;
	private MMBoxManager mmboxManager;
	private UserDBManager userDB;
	
	public HttpProcess(Socket connectionSocket) {
		this.connectionSocket = connectionSocket;
		this.inFromClient = null;
		this.outToClient = null;
		this.pushTempBox = new PushTempBox();
		this.pduMsgBox = new PDUMSGBox();
		this.mmboxManager = new MMBoxManager();
		this.userDB = new UserDBManager();
	}

	@Override
	public void run(){
		System.out.println("WebServer Thread Created");

		try {
			// 클라이언트와 통신을 위한 입/출력 2개의 스트림을 생성한다.
			inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
			outToClient = new DataOutputStream(connectionSocket.getOutputStream());

			// 클라이언트로의 메시지중 첫번째 줄을 읽어들인다.
			requestMessageLine = inFromClient.readLine();
			System.out.print(requestMessageLine);
			// 파싱을 위한 토큰을 생성한다.
			tokenizedRequestLine = new StringTokenizer(requestMessageLine);
			String httpMethod = tokenizedRequestLine.nextToken();

			// POST Method Process
			if (httpMethod.equals("POST")) {
				System.out.println("POST IN");
				//--------------------------------From Client Message Start--------------------------------//
				System.out.println("-----From client11----");
				requestMessageLine = inFromClient.readLine();
				System.out.println(requestMessageLine);
				requestMessageLine = inFromClient.readLine();
				System.out.println(requestMessageLine);
				requestMessageLine = inFromClient.readLine();
				System.out.println(requestMessageLine);
				tokenizedRequestLine = new StringTokenizer(requestMessageLine);
				tokenizedRequestLine.nextToken();

				strContentLength = tokenizedRequestLine.nextToken();
				contentLength = Integer.parseInt(strContentLength);

				char arr[] = new char[contentLength];
				inFromClient.read(arr);
				mmsBody = new String(arr);
				System.out.println(mmsBody);
				System.out.println("-----From client22----");
				//--------------------------------From Client Message End--------------------------------//
				
				//PDU Type Check
				String MMSType = PDUTypeCheck(mmsBody);
				System.out.println(MMSType +" : " +MMS_MESSAGE_TYPE_SEND_REQ);
				//--------------------------------MMSBody parsing Start--------------------------------//
				if(MMSType.equals(MMS_MESSAGE_TYPE_SEND_REQ))
				{	
					System.out.println("Send Req Parsing Part");
					try {
						sendReqMsg = new SendReq(mmsBody);
						sendReqMsg.decodeMessage();
						sendReqMsg.StoreMMS();
						responseHttpMsg = new SendConf();
						responseHttpMsg.setTransactionID(sendReqMsg.getTransactionId());
						responseHttpMsg.setVersion("1.0");
						responseHttpMsg.setResponseStatus("OK");
						responseHttpMsg.setMessageID(sendReqMsg.getMessageId());

						NotificationInd notificationInd = new NotificationInd();
						notificationInd.setTransactionID(notificationInd.MakeTransactionId());
						notificationInd.setVersion("1.0");
						notificationInd.setMessageSize("TempmessageSize");
						notificationInd.setMessageExpiryTime(sendReqMsg.getExpiryTime());
						notificationInd.setContentLocationValue(sendReqMsg.getContentLocation());
						notificationInd.setMessageSender(sendReqMsg.getFrom(),"");
						notificationInd.setMessageSubject(sendReqMsg.getSubject());
						notificationInd.setStore(sendReqMsg.getStore());
						
						System.out.println("saved notification : ");
						System.out.println(notificationInd.toString());

						pduMsgBox.ConnectDB();
						pduMsgBox.StorePduMessage(sendReqMsg.getMessageId(), notificationInd.getTransactionID());
						pduMsgBox.CloseConnectionDB();
						pushTempBox.ConnectDB();
						pushTempBox.StorePduMessage(notificationInd.toString(), sendReqMsg.getFrom(), responseHttpMsg.getMessageID());
						pushTempBox.CloseConnectionDB();
					} catch (MmsMessageException e) {
						e.printStackTrace();
					}
					System.out.println("Server reply conf msg");
					System.out.println(responseHttpMsg.toString());
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_READ_REPOSRT_REQ))
				{
					try {					
					readRecIndMsg = new ReadRecInd(mmsBody);
					readRecIndMsg.decodeMessage();
					
					mmboxManager.ConnectDB();
					String [] msg = mmboxManager.getMsgSenderReceiverInfo(readRecIndMsg.getMessageId(),readRecIndMsg.getTo() , readRecIndMsg.getFrom());
					mmboxManager.CloseConnectionDB();
					if(msg[6] == "true" && readRecIndMsg.getReadStatus() == "yes")
					{
							ReadOrigInd readOrigIndMsg = new ReadOrigInd();
							readOrigIndMsg.setVersion("1.0");
							readOrigIndMsg.setMessageID(readRecIndMsg.getMessageId());
							readOrigIndMsg.setReadMmsTo(readRecIndMsg.getTo());
							readOrigIndMsg.setReadFrom(readRecIndMsg.getFrom());
							readOrigIndMsg.setReadStatus(readRecIndMsg.getReadStatus());
							readOrigIndMsg.setMessageDate(readRecIndMsg.getDate());
							
							System.out.println("saved readOrigIndMsg : ");
							System.out.println(readOrigIndMsg.toString());

							//pduMsgBox.ConnectDB();
							//pduMsgBox.StorePduMessage(readOrigIndMsg.getMessageID(), readOrigIndMsg.getTransactionID());
							//pduMsgBox.CloseConnectionDB();
							pushTempBox.ConnectDB();
							pushTempBox.StorePduMessage(readOrigIndMsg.toString(), readOrigIndMsg.getFrom(), readOrigIndMsg.getMessageID());
							pushTempBox.CloseConnectionDB();
					}
					} catch (MmsMessageException e) {
						e.printStackTrace();
					}
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_FORWAD_REQ))
				{
					try {		
						forwardReqMsg = new ForwardReq(mmsBody);
						forwardReqMsg.decodeMessage();
						forwardReqMsg.StoreMMS();
						responseHttpMsg = new ForwardConf();
						responseHttpMsg.setTransactionID(forwardReqMsg.getTransactionId());
						responseHttpMsg.setVersion("1.0");
						responseHttpMsg.setResponseStatus("OK");
						responseHttpMsg.setMessageID(forwardReqMsg.getMessageID());

						/*
						mmboxManager.ConnectDB();
						String [] msg = mmboxManager.getMsgSenderReceiverInfo(readRecIndMsg.getMessageId(),readRecIndMsg.getTo() , readRecIndMsg.getFrom());
						mmboxManager.CloseConnectionDB();
						if(msg[6] == "true" && readRecIndMsg.getReadStatus() == "yes")
						if(forwardReqMsg.getReportAllowed() == true && )
						NotificationInd notificationInd = new NotificationInd();
						notificationInd.setTransactionID(notificationInd.MakeTransactionId());
						notificationInd.setVersion("1.0");
						notificationInd.setMessageSize("TempmessageSize");
						notificationInd.setMessageExpiryTime(forwardReqMsg.getExpiryTime());
						notificationInd.setContentLocationValue(forwardReqMsg.getContentLocationValue());
						notificationInd.setMessageSender(forwardReqMsg.getFrom(),"");
						notificationInd.setMessageSubject(forwardReqMsg.getSubject());
						notificationInd.setStore(forwardReqMsg.getStore());
						
						System.out.println("saved notification : ");
						System.out.println(notificationInd.toString());

						pduMsgBox.ConnectDB();
						pduMsgBox.StorePduMessage(forwardReqMsg.getMessageID(), notificationInd.getTransactionID());
						pduMsgBox.CloseConnectionDB();
						pushTempBox.ConnectDB();
						pushTempBox.StorePduMessage(notificationInd.toString(), forwardReqMsg.getFrom(), responseHttpMsg.getMessageID());
						pushTempBox.CloseConnectionDB();						
						*/
						
					} catch (MmsMessageException e) {
						e.printStackTrace();
					}
					System.out.println("Server reply conf msg");
					System.out.println(responseHttpMsg.toString());
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_ACKNOWLEDGE_IND))
				{
					try {					
					acknowledgeIndMsg = new AcknowledgeInd(mmsBody);
					acknowledgeIndMsg.decodeMessage();

					mmboxManager.ConnectDB();
					pduMsgBox.ConnectDB();
					userDB.ConnectionDB();
					
					String messageID = pduMsgBox.GetMessageID(acknowledgeIndMsg.getTransactionId());
					String to = userDB.GetUserID(connectionSocket.getInetAddress().toString());
					
					if(mmboxManager.GetDeliveryAllowed(to, messageID).equals("true") && 
							acknowledgeIndMsg.getReportAllowed()==true) {
						
						DeliveryInd deliveryInd = new DeliveryInd();
						deliveryInd.setVersion("1.0");
						deliveryInd.setMessageID(messageID);
						deliveryInd.setReadMmsTo(to);
						deliveryInd.setStatus("Retrieved");

						System.out.println("saved deliveryInd : ");
						System.out.println(deliveryInd.toString());

						mmboxManager.CloseConnectionDB();
						pduMsgBox.CloseConnectionDB();
						userDB.CloseConnectionDB();
						
						pushTempBox.ConnectDB();
						pushTempBox.StorePduMessage(deliveryInd.toString(), deliveryInd.getFrom(), deliveryInd.getMessageID());
						pushTempBox.CloseConnectionDB();
					}
					
					} catch (MmsMessageException e) {
						e.printStackTrace();
					}
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_NOTIFY_IND))
				{
					try {					
						
						notifyRespMsg = new NotifyResp(mmsBody);
						notifyRespMsg.decodeMessage();
						notifyRespMsg.getTransactionId();
						notifyRespMsg.getStatus();
						notifyRespMsg.getReportAllowed();
						
						} catch (MmsMessageException e) {
							e.printStackTrace();
						}
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_ACKNOWLEDGE_IND))
				{
					
				}
				else if (MMSType.equals(MMS_MESSAGE_TYPE_ACKNOWLEDGE_IND))
				{
					
				}
				else
					System.out.println("Not Supported Msg Type");

				//--------------------------------MMSBody parsing End--------------------------------//
				
				//--------------------------------Response to Client  Start--------------------------------//
				outToClient.writeBytes("HTTP/1.1 200 OK \r\n");
				outToClient.writeBytes("Content-Type: "+ "application/vnd.wap.mms-message" + "\r\n");
				outToClient.writeBytes("Content-Length: " + responseHttpMsg.toString().length() + "\r\n");
				if(responseHttpMsg != null)
				{
					outToClient.writeBytes("\r\n");
					outToClient.writeBytes(responseHttpMsg.toString());
				}
				//--------------------------------Response to Client response End--------------------------------//
			} 
			else if (httpMethod.equals("GET")) {
				ProcessGetMethod();
			}
			else {
				outToClient.writeBytes("HTTP/1.1 400 Bad Request Message \r\n");
				connectionSocket.close();
				outToClient.writeBytes("Connection: close\r\n");
			} 
			System.out.println("Connection Closed");
		}
			catch (IOException ioe) {
			ioe.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void ProcessGetMethod() throws IOException
	{
		System.out.println("-----From client33----");
		requestMessageLine = inFromClient.readLine();
		System.out.println(requestMessageLine);
		requestMessageLine = inFromClient.readLine();
		System.out.println(requestMessageLine);
		String filePath = tokenizedRequestLine.nextToken();
		
  if(filePath.startsWith("/") == true){
	  if(filePath.length() > 1)		          
		  filePath = filePath.substring(1);
          }

		responseHttpMsg = new RetrieveConf(filePath);

		// 요청한 파일이 존재하는가?
		if (responseHttpMsg.isExistFile() == true) {
			// 정상적으로 처리가 되었음을 나타내는 200 코드를 출력한다.
			outToClient.writeBytes("HTTP/1.1 200 OK \r\n");
			outToClient.writeBytes("Content-Type: " + "application/vnd.wap.multipart.mixed" + "\r\n");
			
			this.responseHttpMsg.setMessageDate("latest submission or forwarding Date"); // latest submission or forwarding Date 
			this.responseHttpMsg.setMessageID(filePath);
			this.responseHttpMsg.setRetrieveStatus("OK");
			
			String mmBody = responseHttpMsg.toString();
			//mmBody.length();
			// 출력할 컨텐츠의 길이를 출력
			outToClient.writeBytes("Content-Length: " + mmBody.length() + "\r\n");
			outToClient.writeBytes(mmBody);
			//connectionSocket.close();
		}
	}
	
	public String PDUTypeCheck(String mmsBody)
	{
		tokenizedMmsBody = new StringTokenizer(mmsBody);
		String firstBodyLine = tokenizedMmsBody.nextToken(NL);
		tokenizedMmsBody = new StringTokenizer(firstBodyLine);
		tokenizedMmsBody.nextToken();
		return tokenizedMmsBody.nextToken();
	}
}
